/**************************************************************************//**
 * @file     system_NUC029xDE.c
 * @version  V3.0
 * $Revision: 4 $
 * $Date: 14/07/22 9:41a $
 * @brief    NUC029xDE Series CMSIS System File
 *
 * @note
 * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
 *
 ******************************************************************************/
#include <stdint.h>
#include "NUC029xDE.h"

#define XTAL_ENABLE 1
/*----------------------------------------------------------------------------
  Clock Variable definitions
 *----------------------------------------------------------------------------*/
uint32_t SystemCoreClock  = __HSI;             /*!< System Clock Frequency (Core Clock) */
uint32_t CyclesPerUs      = (__HSI / 1000000); /* Cycles per micro second */
uint32_t PllClock         = __HSI;             /*!< PLL Output Clock Frequency */
uint32_t gau32ClkSrcTbl[] = {__HXT, NULL, __HSI, __LIRC, NULL, NULL, NULL, __HIRC};


/*----------------------------------------------------------------------------
  Clock functions
  This function is used to update the variable SystemCoreClock
  and must be called whenever the core clock is changed.
 *----------------------------------------------------------------------------*/
void SystemCoreClockUpdate(void)             /* Get Core Clock Frequency      */
{
    uint32_t u32Freq, u32ClkSrc;
    uint32_t u32HclkDiv;

    /* Update PLL Clock */
    PllClock = CLK_GetPLLClockFreq();

    u32ClkSrc = CLK->CLKSEL0 & CLK_CLKSEL0_HCLK_S_Msk;

    if(u32ClkSrc != CLK_CLKSEL0_HCLK_S_PLL)
    {
        /* Use the clock sources directly */
        u32Freq = gau32ClkSrcTbl[u32ClkSrc];
    }
    else
    {
        /* Use PLL clock */
        u32Freq = PllClock;
    }

    u32HclkDiv = (CLK->CLKDIV & CLK_CLKDIV_HCLK_N_Msk) + 1;

    /* Update System Core Clock */
    SystemCoreClock = u32Freq / u32HclkDiv;

    CyclesPerUs = (SystemCoreClock + 500000) / 1000000;
}

/*---------------------------------------------------------------------------------------------------------*/
/* Function: SystemInit                                                                                    */
/*                                                                                                         */
/* Parameters:                                                                                             */
/*      None                                                                                               */
/*                                                                                                         */
/* Returns:                                                                                                */
/*      None                                                                                               */
/*                                                                                                         */
/* Description:                                                                                            */
/*      The necessary initialization of system.                                                           */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/
void SystemInit(void)
{
    int32_t i32TimeoutCnt;
    uint32_t u32HclkSelect;
    int8_t i8IsPllEn;

    PllClock = 0;
    i8IsPllEn = 0;
    u32HclkSelect = CLK->CLKSEL0 & CLK_CLKSEL0_HCLK_S_Msk;
    if(u32HclkSelect == CLK_CLKSEL0_HCLK_S_HXT)
    {
        /* Set to 50MHz system clock frequency when clock source is from external 12MHz */
        //CLK->PLLCON = CLK_PLLCON_50MHz_HXT;
        // 11059200*48/3/4 = 44236800
        CLK->PLLCON =  (CLK_PLLCON_PLL_SRC_HXT  | CLK_PLLCON_NR(3)  | CLK_PLLCON_NF( 48) | CLK_PLLCON_NO_4);
        /* Waiting for PLL ready */
        i32TimeoutCnt = (__HXT / 1000); /* Timeout is about 1ms */
        while((CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk) == 0)
        {
            if(i32TimeoutCnt-- <= 0)
                break;
        }

        i8IsPllEn = 1;
    }
    else if(u32HclkSelect == CLK_CLKSEL0_HCLK_S_HIRC)
    {
#if XTAL_ENABLE > 0
		SYS_UnlockReg();
		CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;
		i32TimeoutCnt = (__HIRC / 50);                        /* Timeout is about 1ms */
		while((CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk) == 0)
        {
            if(i32TimeoutCnt-- <= 0)
                break;
        }
		
		SYS_LockReg();
		
        /* Set to 50MHz system clock frequency when clock source is from external 12MHz */
        //CLK->PLLCON = CLK_PLLCON_50MHz_HXT;
        // 11059200*48/3/4 = 44236800
        CLK->PLLCON =  (CLK_PLLCON_PLL_SRC_HXT  | CLK_PLLCON_NR(3)  | CLK_PLLCON_NF( 48) | CLK_PLLCON_NO_4);
        /* Waiting for PLL ready */
        i32TimeoutCnt = (__HXT / 1000); /* Timeout is about 1ms */
        while((CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk) == 0)
        {
            if(i32TimeoutCnt-- <= 0)
                break;
        }
        i8IsPllEn = 1;
#else
        /* Set to 50.1918MHz system clock frequency when clock source is from internal 22.1184MHz RC clock */
        CLK->PLLCON = CLK_PLLCON_50MHz_HIRC;

        /* Waiting for PLL ready */
        i32TimeoutCnt = (__HIRC / 1000); /* Timeout is about 1ms */
        while((CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk) == 0)
        {
            if(i32TimeoutCnt-- <= 0)
                break;
        }
        i8IsPllEn = 1;
#endif		
    }

    if(i8IsPllEn)
    {
        /* Set PLL as HCLK clock source (HCLK_S is locked setting)*/
        SYS_UnlockReg();
		CLK->CLKSEL0 = CLK_CLKSEL0_HCLK_S_PLL | CLK_CLKSEL0_STCLK_S_HCLK_DIV2;
        SYS_LockReg();
    }
}
